import { ComparisonHandler, Heap, comparisonHandler, getTimeoutHandler } from "./heap";

export interface TimerOptions<T> {
    comparisonHandler?: ComparisonHandler<T>,
    getTimeoutHandler?: ComparisonHandler<T, number>,
}
export class Timer<T extends { cb: Function }> {
    _opts: TimerOptions<Task<T>>;
    _getTimeoutHandler: ComparisonHandler<Task<T>, number>;
    _heap: Heap<Task<T>>;
    _timeoutId: any;
    _taskMap: any;
    constructor(opts: TimerOptions<Task<T>> = {}) {
        this._opts = opts;

        let ch = this._opts.comparisonHandler
            ? this._opts.comparisonHandler
            : comparisonHandler;

        this._getTimeoutHandler = this._opts.getTimeoutHandler
            ? this._opts.getTimeoutHandler
            : getTimeoutHandler;

        this._heap = new Heap(ch);
        this._timeoutId = null;
        // 未执行的任务 key
        this._taskMap = Object.create(null);
    }

    _reset() {
        if (this._timeoutId) {
            clearTimeout(this._timeoutId);
            this._timeoutId = null;
        }
    }

    _createTimer() {
        this._reset();
        const timeout = this._getTimeoutHandler(this._heap.peep());
        if (timeout < 0) return;
        this._timeoutId = setTimeout(this._executeHandler.bind(this), timeout);
    }

    _executeHandler() {
        let currentHandleData = this._heap.removeMin();
        this._removeTaskMap(currentHandleData.key);
        currentHandleData && currentHandleData.cb && currentHandleData.cb();
        if (!this._heap.empty()) {
            this._createTimer();
        }
    }

    _removeTaskMap(key: string) {
        if (this._taskMap[key]) {
            delete this._taskMap[key];
        }
    }

    _getIndexByKey(key: string) {
        const list = this._heap.getList();
        return list.findIndex(task => {
            if (task) return task.key === key;
        });
    }

    set(key: string, opts: any) {
        if (this._taskMap[key]) {
            console.log(`当前 key 已存在：${key}`);
            return;
        }
        this._taskMap[key] = true;
        this._heap.insert(new Task(key, opts));
        this._createTimer();
    }

    delete(key: string) {
        if (!this._taskMap[key]) {
            console.log(`不存在的 key :${key}`);
            return;
        }
        let index = this._getIndexByKey(key);
        this._heap.removeByIndex(index);
    }

    clear() {
        this._taskMap = Object.create(null);
        this._reset();
        this._heap.reset();
    }
};

export class Task<T extends { cb: Function, [key: string]: any }> {
    key: string;
    _opts: T;
    date: Date = new Date();
    constructor(key: string, opts: T) {
        this.key = key;
        this._opts = opts;
        if (opts.date) {
            this.date = opts.date;
        }
    }
    get cb() {
        return this._opts.cb
    }
}

export const defaultTimer = new Timer({
    comparisonHandler: (a, b) => {
        return a.date.getTime() > b.date.getTime()
    },
    getTimeoutHandler: (a, b) => {
        return a.date.getTime() - new Date().getTime()
    }
})

